<?php


namespace app\api\service;
use app\enum\OrderStatusEnum;
use app\exception\OrderException;
use app\exception\TokenException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use app\api\model\Order as OrderModel;
use app\api\service\Order as OrderService;
use think\Log;

spl_autoload_register('auto_load_class'); //spl注册自动加载

class Pay
{
    private $orderID;
    private $orderNO;

    /**
     * Pay constructor.
     *
     * @param $orderID
     *
     * @throws Exception
     */
    function __construct($orderID){
        if(!$orderID){
            throw new Exception("订单号不允许为空");
        }
        $this->orderID = $orderID;
    }

    /**
     *
     * @throws DataNotFoundException
     * @throws DbException
     * @throws Exception
     * @throws ModelNotFoundException
     * @throws OrderException
     * @throws TokenException
     * @throws \WxPayException
     */
    public function pay(): array
    {
        //订单号可能根本就不存在
        //订单号确实存在，但是订单号和当前用户是不匹配
        //订单有可能已经被支付过了
        //当前库存量检测
        $this->checkOrderValid();
        $orderService = new OrderService();
        $status = $orderService->checkOrderStock($this->orderID);
        if(!$status['pass']){
            return $status;
        }
        return $this->makeWxPreOrder($status['orderPrice']);
    }

    /**
     * @throws Exception
     * @throws TokenException
     * @throws \WxPayException
     */
    private function makeWxPreOrder($totalPrice): array
    {
        // openid
        $openid = Token::getCurrentTokenVar('openid');
        if(!$openid){
            throw new TokenException();
        }
        // 设置 统一下单输入对象
        $wxOrderData = new \WxPayUnifiedOrder();
        $wxOrderData->SetOut_trade_no($this->orderNO); //订单号
        $wxOrderData->SetTrade_type('JSAPI');  //交易类型
        $wxOrderData->SetTotal_fee($totalPrice*100); //交易总金额  以分为单位
        $wxOrderData->SetBody('零食商贩');
        $wxOrderData->SetOpenid($openid);
        //异步接收微信支付结果通知的回调地址，通知url必须为外网可访问的url，不能携带参数。
        $wxOrderData->SetNotify_url(config('secure.pay_back_url'));
        return $this->getPaySignature($wxOrderData);
    }
    // 调用微信预订单接口

    /**
     * @param $wxOrderData
     *
     * @return array
     * @throws \WxPayException
     */
    private function getPaySignature($wxOrderData): array
    {
        $config = new \WxPayConfig();
        $wxOrder = \WxPayApi::unifiedOrder($config,$wxOrderData);
//        var_dump($wxOrder['sign']);
        if($wxOrder['return_code']!='SUCCESS'||
           $wxOrder['result_code']!='SUCCESS'
        ){
            \think\facade\Log::record($wxOrder,'error');
            \think\facade\Log::record("获取预支付订单失败",'error');
        }
        //prepay_id 微信生成的预支付会话标识，用于后续接口调用中使用，该值有效期为2小时
        $this->recordPreOrder($wxOrder);
        return $this->sign($wxOrder);
    }
    private function sign($wxOrder){
        $config = new \WxPayConfig();
        $jsApiPayData = new \WxPayJsApiPay();
        $jsApiPayData->SetAppid(config('wx.app_id'));
        $jsApiPayData->SetTimeStamp((string)time());
        $rand = md5(time().mt_rand(0,1000));
        $jsApiPayData->SetNonceStr($rand);
        $jsApiPayData->SetPackage('prepay_id ='.$wxOrder['prepay_id']);
        $jsApiPayData->SetSignType('md5');
        $sign = $jsApiPayData->MakeSign($config );
        $rawValues = $jsApiPayData->GetValues();
        $rawValues['paySign'] = $sign;
        unset($rawValues['appId']);
        return $rawValues;
    }
    private function recordPreOrder($wxOrder){
        OrderModel::where('id','=',$this->orderID)->update(
          ['prepay_id'=>$wxOrder['prepay_id']]
        );
    }
    /**
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws OrderException
     * @throws TokenException|Exception
     */
    private function checkOrderValid(){
        $order = OrderModel::where('id','=',$this->orderID)->find();
        if(!$order){
            throw new OrderException();
        }
        if(!Token::isValidOperate($order->user_id)){
            throw new TokenException(
                ['msg'=>'订单与用户不匹配',
                 'errorCode' =>10003]
            );
        }
        if($order->status!=OrderStatusEnum::UNPAID){
            throw new OrderException([
                'msg'=>'订单以被支付过',
                'errorCode'=>80003,
                'code'=>400
            ]);
        }
        $this->orderNO = $order->order_no;
        return true;
    }
}